<template>
  <div class="workFlow" @contextmenu="() => false" id="workflowDetail">
    <div class="workFlow_headers">
      <div class="title-t">
        <div class="nowName">当前工作流：<span>{{ routeParams.flowName }}</span></div>
        <span type="link" class="checkWorkflow" @click="checkWorkflowChat">检测工作流完整性</span>
        <div class="workFlow_headers_button">
          <a-button class="addButton" @click="toggleFullscreen">
            {{ !fullScreen ? "全屏" : "取消全屏" }}
          </a-button>
          <a-button class="addButton" type="primary" 
          :disabled="!btnPerm.includes('saveAble')"
          @click="saveWorkFlow">
            保存
          </a-button>
        </div>
      </div>

    </div>
    <div class="workFlow_content">
      <div class="workFlow_content_left">
        <div class="drag-wrap">
          <div class="title">
            <span>流程组件库</span>
          </div>
          <div id="begin" title="开始" @dragstart="nodeDragStart" class="flow-node" draggable="true">
            <div class="begin">开始</div>
          </div>
          <div id="audit" title="审核" @dragstart="nodeDragStart" class="flow-node" draggable="true">
            <div class="audit">审核</div>
          </div>
          <div id="end" title="结束" @dragstart="nodeDragStart" class="flow-node" draggable="true">
            <div class="end">结束</div>
          </div>
          <div class="workflow-rule-wrap">
            <a-tooltip color="#fff" overlayClassName="a-tooltip-color">
              <template #title>
                <span>
                  1、 整个流程必须闭合（有从开始到结束完整
                  的连线）且不存在孤立节点<br />
                  2、开始节点只能连接审核节点且只能连一个 <br />
                  3、点击连接线或对应节点可以进行相应配置 <br />
                  4、开始节点与结束节点不能删除<br /></span>
              </template>
              <div class="jee-border">规则<br />说明</div>
            </a-tooltip>
          </div>
        </div>
      </div>
      <div class="workFlow_content_middle" @drop="toElementDrop" @dragover="onDragOver">
        <G6Comp ref="G6Comp_ref" :lineType="lineType" :currentNode="currentNode" @getCurrentNode="getCurrentNode"
          @checkFlowEdgeConfig="checkFlowEdgeConfig" :selectItemId="selectItemId" :workFlowData="workFlowData"
          :refresh="refresh" :validForm="checkSettingForm">
        </G6Comp>
      </div>
      <div class="workFlow_content_right" v-if="settingComp">
        <div class="title">组件配置</div>
        <component :is="settingComp" @changeBENodeName="getCurrentNode" :hiddenAllowRevoke="hiddenAllowRevoke"
          :currentNode="currentNode" ref="getFormInfo">
        </component>
      </div>
    </div>
    <ul id="contextMenu">
      <li @click="handleDelete">删除</li>
    </ul>
  </div>
</template>
<script lang="ts" setup>
import { ref, onMounted, nextTick, watch } from "vue";
import { randomWord } from "@/utils/common";
import G6Comp from "./G6/G6.vue";
import { useRoute } from "vue-router";
import { message } from "ant-design-vue";
import request from "@/api/index";
import auditNodeSetting from "./settings/auditNodeSetting.vue";
import lineSetting from "./settings/lineSetting.vue";
import screenfull from "screenfull";
import {routerPerm} from '@/utils/common';
// ts
interface propoties {
  [propName: string]: any;
}
// data
const btnPerm = ref<any[]>([]);
// 路由参数
const routeParams: propoties = useRoute().query;
//data .oncontextmenu
//流程图数据
const fullScreen = ref<Boolean>(false);
const workFlowData = ref<propoties>({});
const G6Comp_ref = ref();
const graph = ref<any>("");
const lineType = ref<string>("k-edge");
const mode = ref<string>("default");
const currentNode = ref<propoties>({}); // 当前节点或线的数据
const selectItemId = ref<propoties>({}); // 当前节点或线id，
const nodeTypes = ref<string[]>(["begin", "audit", "end", "line", "beginline"]);
const hiddenAllowRevoke = ref<any>(false); // 线的允许撤回功能
// 设置项组件
const settingComp = ref<any>("");
const getFormInfo = ref();
const SettingForm = ref<Boolean>(true);
const actions = ref<propoties[]>([]);
// 保存成功
const refresh = ref<Boolean | any>(false);
//onMounted
onMounted(() => {
  btnPerm.value = routerPerm()
  let contextMenu = document.getElementById("contextMenu");
  contextMenu &&
    contextMenu.addEventListener("mouseout", (e: propoties) => {
      contextMenu && (contextMenu.style.display = "none");
    });
});
watch(
  () => currentNode.value.form?.name, // 单独监听线的名称信息， 全部监听会很卡
  (newData, oldData) => {
    // 当前配置面板修改数据，更新对应的节点model
    const id = currentNode.value.id;
    if (id && typeof oldData !== "undefined") {
      const node = G6Comp_ref.value.graph.findById(id);
      if (node) {
        G6Comp_ref.value.graph.updateItem(node, {
          label: newData,
          form: {
            name: newData,
          },
        });
      }
    }
  }
);
watch(
  () => currentNode.value.actionCode, // 单独监听线的性质信息
  (newData, oldData) => {
    // 当前配置面板修改数据，更新对应的节点model
    if (newData) {
      const id = currentNode.value.id;
      if (id) {
        const node = G6Comp_ref.value.graph.findById(id);
        node._cfg.model.actionCode = newData;
        if (node) {
          G6Comp_ref.value.graph.updateItem(node, {});
        }
      }
    }

  }
);

// methods
// toggle全屏显示
const toggleFullscreen = () => {
  if (screenfull.isEnabled) {
    // screenfull.toggle();
    fullScreen.value = !fullScreen.value;
    if (fullScreen.value) {
      document.getElementById("workflowDetail")?.requestFullscreen();
    } else {
      document.exitFullscreen();
    }
  }
};

// 生成默认表单
const getDefaultForm = (nodeType: string) => {
  switch (nodeType) {
    case "audit":
      return {
        id: "",
        name: "",
        isAssignReviewers: false, //发起人是否可以指定审核人员
        isAutoRevoke: false, //	是否开启超时自动撤回
        isEditAuditTarget: false, //	是否允许审核人员编辑审核内容
        isRevoke: false, //发起人是否可以撤回审核
        isUrgeReviewer: false, //发起人是否可以催审
        jointlyPassRatio: "", //	会签通过比例(1-100)
        jointlySign: false, //是否是会签节点
        jointlyType: 1, //
        notifyTypes: [], //催办通知发送到审核员方式 1：站内信 2：短信通知 3：邮件通知
        timeout: "", //超时自动撤回的超时时间(单位：小时)
        reviewers: [], //审核人员
        nodeType: "",
        actions: [
          {
            label: "通过",
            value: "agree",
            disabled: false,
          },
          {
            label: "不通过",
            value: "disagree",
            disabled: false,
          },
        ],
      };
    case "beginline":
      return {
        id: "",
        name: "",
        line: "beginline",
      };
    case "line":
      return {
        id: "",
        name: "",
        notifyTypes: [],
        requireReviewComment: false,
        line: "line",
      };
    default:
      return {
        id: "",
        name: "",
      };
  }
};
// 开始拖拽图形
const nodeDragStart = (ev: propoties) => {
  mode.value = "default";
  ev.dataTransfer.setData("nodeType", ev.target.id);
  ev.dataTransfer.setData("targetTitle", ev.target.title);
  //ev.dataTransfer.setDragImage(this.dragImg, 80, 40)
};
// 放下拖拽图形
const toElementDrop = (ev: any) => {
  ev.preventDefault();
  const nodeType = ev.dataTransfer.getData("nodeType");
  if (!checkNodeType(nodeType)) return false;
  if (!checkFlowData(nodeType)) return false;
  let result = checkSettingForm();
  if (result === true) {
    setNode(ev, nodeType);
  } else {
    result
      .validate()
      .then(() => {
        setNode(ev, nodeType);
      })
      .catch((err: any) => {
        message.error("请检查当前节点或连接线配置是否填写正确！");
        // setTimeout(() => {
        //   let errors = document.querySelector('.ant-form-item-explain-error');
        //   errors?.scrollIntoView({
        //     behavior: 'smooth',
        //     block: 'start'
        //   })
        // }, 1)
      });
  }
  return false;
};
const setNode = (ev: any, nodeType: any) => {
  const shape = nodeType + "Node";
  const type = nodeType + "Node";
  const id = randomWord(false, 4, 4);
  const title = ev.dataTransfer.getData("targetTitle");
  let form = getDefaultForm(nodeType);
  form.id = id;
  form.name = title;
  form.nodeType = nodeType;
  const point = G6Comp_ref.value.graph.getPointByClient(ev.clientX, ev.clientY);
  G6Comp_ref.value.graph.addItem("node", {
    id,
    label: title,
    nodeType,
    x: point.x,
    y: point.y,
    type,
    nodeCode: id,
    shape,
    form,
  });
  // const node = G6Comp_ref.value.graph.findById(id);
  // if (node) {
  //   currentNode.value = node.getModel();
  // }
};
// 拖拽图形hover时
const onDragOver = (ev: propoties) => {
  ev.preventDefault();
};
const checkNodeType = (nodeType: string) => {
  return nodeTypes.value.includes(nodeType);
};
// 检查添加图形
const checkFlowData = (nodeType: string) => {
  if (["begin", "end"].includes(nodeType)) {
    const findNode = G6Comp_ref.value.graph.find("node", (node: any) => {
      return !node.destroyed && node.get("model").nodeType === nodeType;
    });
    if (findNode) {
      message.warning(
        nodeType === "begin" ? "只能添加一个开始节点" : "只能添加一个结束节点"
      );
      return false;
    }
  }
  return true;
};
// 检查当前配置表单
const checkSettingForm = () => {
  let result = true;
  if (!getFormInfo.value || !getFormInfo.value.Setting) {
    result = true;
    return result;
  } else {
    let baseForm = getFormInfo.value.Setting.baseForm;
    return baseForm;
  }
};
// 删除连接线 右键删除节点或线
const handleDelete = () => {
  if (G6Comp_ref.value.selectItemId.id) {
    const item = G6Comp_ref.value.graph.findById(
      G6Comp_ref.value.selectItemId.id
    );
    if (item) {
      G6Comp_ref.value.graph.removeItem(item);
      selectItemId.value = {};
      G6Comp_ref.value.graph.refresh();
    }
    if (G6Comp_ref.value.selectItemId.id == currentNode.value.id) {
      currentNode.value = {};
      settingComp.value = "";
    }
  }
  const menu = document.getElementById("contextMenu");
  menu && (menu.style.left = "-100px");
};
// 提交前检查，必须包含开始、结束
const checkBeforeSubmit = () => {
  const begin = G6Comp_ref.value.graph.find("node", (node: propoties) => {
    return node.get("model").nodeType === "begin";
  });
  if (!begin) {
    message.error("必须要有开始节点");
    return false;
  } else {
    if (!begin.getOutEdges().length) {
      message.error("开始节点必须要有出线");
      return false;
    }
  }
  const end = G6Comp_ref.value.graph.find("node", (node: propoties) => {
    return node.get("model").nodeType === "end";
  });
  if (!end) {
    message.error("必须要有结束节点");
    return false;
  } else {
    if (!end.getInEdges().length) {
      message.error("结束节点必须要有入线");
      return false;
    }
  }
  const audit = G6Comp_ref.value.graph.find("node", (node: propoties) => {
    return node.get("model").nodeType === "audit";
  });
  if (!audit) {
    message.error("必须要有审核节点");
    return false;
  }
  return true;
};
// 检查边配置
const checkFlowEdgeConfig = (edge: propoties) => {
  const model = edge.getModel();
  const sourceNode = edge.getSource().getModel();
  if (typeof model.target === "string") {
    const targetNode = edge.getTarget().getModel();
    // 指向开始结束点的连线不能设撤回
    hiddenAllowRevoke.value = ["begin", "end"].includes(targetNode.nodeType);
  }
  // 同一审核节点不能有同样的动作
  if (sourceNode.nodeType === "audit") {
    let action: any[] = [];
    edge
      .getSource()
      .getOutEdges()
      .forEach((edge: propoties) => {
        if (!edge.destroyed && edge.getModel().id !== model.id) {
          action.push(edge.getModel().form.actionCode);
        }
      });
    actions.value = action;
  }
};
// 获取当前节点
const getCurrentNode = (val: any) => {
  if (val.nodeType == "audit") {
    settingComp.value = auditNodeSetting;
  } else if (val.nodeType == "line" || val.nodeType == "beginline") {
    settingComp.value = lineSetting;
  } else {
    settingComp.value = "";
  }
  currentNode.value = val;
};
// 检测工作流完整性
const checkWorkflowChat = () => {
  if (!checkBeforeSubmit()) return;
  let result = checkSettingForm();
  if (result === true) {
    testData();
  } else {
    result
      .validate()
      .then(() => {
        testData();
      })
      .catch((err: any) => {
        message.error("请检查当前节点或连接线配置是否填写正确！");
      });
  }

}
// 保存工作流
const saveWorkFlow = () => {
  if (!checkBeforeSubmit()) return;
  let result = checkSettingForm();
  if (result === true) {
    saveData();
  } else {
    result
      .validate()
      .then(() => {
        saveData();
      })
      .catch((err: any) => {
        message.error("请检查当前节点或连接线配置是否填写正确！");
      });
  }
};
const saveData = () => {
  let edges = JSON.parse(JSON.stringify(G6Comp_ref.value.graph.save().edges));
  let nodes = JSON.parse(JSON.stringify(G6Comp_ref.value.graph.save().nodes));
  edges.forEach((item: propoties) => {
    item.lineCode = item.id;
    delete item.id; // id这属性后台要用
  });
  nodes.forEach((item: propoties) => {
    item.nodeCode = item.id; // id这属性后台要用
    delete item.id;
  });
  const params = {
    flowId: +routeParams.id,
    lines: edges,
    nodes: nodes,
  };
  const notifyTypesList = params.nodes.filter((item: any) => item.label == '审核')
  console.log(notifyTypesList,'notifyTypesList');
  
  for (let i = 0; i < notifyTypesList.length; i++) {
    if(notifyTypesList[i].form.isUrgeReviewer && notifyTypesList[i].form.notifyTypes.length < 1) {
      return message.warning('请选择催办方式')
    }
  }
  request
    .updateWorkFlowDetail(params)
    .then((res: propoties) => {
      if (res.code == "00000 00000") {
        if (res.data.hasError) {
          if (Object.keys(res.data.errors).length) {
            for (let i in res.data.errors) {
              message.error(res.data.errors[i]);
            }
          } else {
            //
            let lineNodes = res.data.nodes.concat(res.data.lines);
            let nodeErrors = lineNodes.reduce(
              (arr: any, item: propoties, index: number) => {
                if (Object.keys(item.errors).length) {
                  for (let i in item.errors) {
                    message.error(item.errors[i]);
                  }
                  arr.push(item.node.form.id);
                }
                return arr;
              },
              []
            );
            nodeErrors.forEach((id: any) => {
              const node = G6Comp_ref.value.graph.findById(id);
              G6Comp_ref.value.graph.setItemState(node, "error", true);
            });
          }
        } else {
          refresh.value = true;
          message.success(res.message);
        }
      } else {
        message.error(res.message);
      }
    })
    .catch((err: any) => {
    });
};
const testData = () => {
  let edges = JSON.parse(JSON.stringify(G6Comp_ref.value.graph.save().edges));
  let nodes = JSON.parse(JSON.stringify(G6Comp_ref.value.graph.save().nodes));
  edges.forEach((item: propoties) => {
    item.lineCode = item.id;
    delete item.id; // id这属性后台要用
  });
  nodes.forEach((item: propoties) => {
    item.nodeCode = item.id; // id这属性后台要用
    delete item.id;
  });
  const params = {
    flowId: +routeParams.id,
    lines: edges,
    nodes: nodes,
  };
  request
    .checkWorkflowChat(params)
    .then((res: propoties) => {
      if (res.code == "00000 00000") {
        if (res.data.hasError) {
          if (Object.keys(res.data.errors).length) {
            for (let i in res.data.errors) {
              message.error(res.data.errors[i]);
            }
          } else {
            //
            let lineNodes = res.data.nodes.concat(res.data.lines);
            let nodeErrors = lineNodes.reduce(
              (arr: any, item: propoties, index: number) => {
                if (Object.keys(item.errors).length) {
                  for (let i in item.errors) {
                    message.error(item.errors[i] || '信息不存在！');
                  }
                  arr.push(item.node.form.id);
                }
                return arr;
              },
              []
            );
            nodeErrors.forEach((id: any) => {
              const node = G6Comp_ref.value.graph.findById(id);
              G6Comp_ref.value.graph.setItemState(node, "error", true);
            });
          }
        } else {
          message.success('流程完整！');
        }
      } else {
        message.error(res.message);
      }
    })
    .catch((err: any) => {
    });
}
</script>

<style lang="scss">
.workFlow {
  height: calc(100% - 84px);
  background: #fff;
  padding: 0 24px;
  overflow: hidden;

  .workFlow_headers {
    // display: flex;
    height: 80px;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
    // align-items: center;
    color: rgba(0, 0, 0, 0.85);
    font-size: 14px;

    .title-t {
      height: 100%;
      display: flex;
      align-items: center;
    }

    .nowName {
      color: #7f7f7f;
      font-size: 15px;

      span {
        color: #333;
      }
    }

    .workFlow_headers_title {
      width: auto;
    }

    .workFlow_headers_button {
      flex: 1;
      display: flex;
      justify-content: flex-end;

      .addButton {
        margin-left: 16px;
      }
    }

    .checkWorkflow {
      margin-left: 12px;
      color: var(--theme_text_hightlight_color, #1F6DED);
      text-decoration: underline;
      cursor: pointer;

      &:hover {
        color: var(--theme_text_hightlight_color, #2f54eb);
      }
    }
  }

  .workFlow_content {
    width: 100%;
    height: calc(100% - 80px);
    overflow: hidden;
    display: flex;

    .workFlow_content_left {
      width: 112px;
      height: 100%;
      border-right: 1px solid rgba(0, 0, 0, 0.06);

      .drag-wrap {
        position: relative;
        display: flex;
        align-items: center;
        flex-direction: column;
        padding-right: 23px;

        .title,
        .flow-node {
          margin-top: 24px;
          font-size: 16px;
          font-family: PingFang SC-Medium, PingFang SC;
          font-weight: 600;
          color: rgba(0, 0, 0, 0.85);
        }

        // 拖拽节点
        .begin {
          width: 54px;
          height: 54px;
          background: #ffffff;
          border: 2px solid rgba(0, 0, 0, 0.45);
          border-radius: 100%;
          line-height: 54px;
          text-align: center;
          cursor: move;
        }

        .end {
          width: 88px;
          height: 40px;
          background: #ffffff;
          border-radius: 44px;
          line-height: 40px;
          text-align: center;
          border: 2px solid rgba(0, 0, 0, 0.45);
          cursor: move;
        }

        .audit {
          width: 88px;
          height: 40px;
          background: #ffffff;
          border-radius: 4px 4px 4px 4px;
          line-height: 40px;
          text-align: center;
          border: 2px solid rgba(0, 0, 0, 0.45);
          cursor: move;
        }

        .audit {
          border-radius: 4px;
        }

        .text {
          text-align: center;
        }

        .line {
          height: 0;
          cursor: move;
          width: 60px;
          border-top: 2px solid #666666;
          position: relative;

          .spoint,
          .epoint {
            position: absolute;
            top: -3px;
            height: 4px;
            width: 4px;
            background-color: #666666;
          }

          .spoint {
            left: 0;
          }

          .epoint {
            right: 0;
          }
        }

        .polyline {
          height: 36;
          position: relative;
          display: flex;
          justify-content: space-between;
          width: 60px;

          .line-top,
          .line-bottom {
            height: 0;
            width: 50%;
            border-bottom: 2px solid #666666;
          }

          .line-bottom {
            height: 38px;
            border-left: 2px solid #666666;
          }

          .spoint,
          .epoint {
            position: absolute;
            height: 4px;
            width: 4px;
            background-color: #666666;
          }

          .spoint {
            left: 0;
            top: -1px;
          }

          .epoint {
            right: 0;
            bottom: -1px;
          }
        }

        &.flow-node-line {
          cursor: move;
          width: 60px;
        }

        .workflow-rule-wrap {
          margin-top: 24px;
          border-top: 1px solid rgba(0, 0, 0, 0.06);

          .jee-border {
            margin-top: 24px;
            width: 60px;
            height: 60px;
            background: #edf7ff;
            opacity: 1;
            border-radius: 100%;
            cursor: pointer;
            font-size: 14px;
            padding: 14px 16px;
            line-height: 17px;
          }
        }
      }
    }

    .workFlow_content_middle {
      overflow: hidden;
      flex: 1;
      height: 100%;

      #mountNode {
        overflow: auto;
        height: 100%;
        width: 100%;
        position: relative;
        z-index: 1;
      }
    }

    .workFlow_content_right {
      width: 328px;
      overflow-y: scroll;
      height: 100%;
      border-left: 1px solid rgba(0, 0, 0, 0.06);
      padding: 23px;
      padding-right: 0px;

      .title {
        padding-bottom: 8px;
        border-bottom: 1px solid rgba(0, 0, 0, 0.06);
      }
    }
  }

  #contextMenu {
    z-index: 1;
    position: absolute;
    list-style: none;
    padding: 5px 0;
    color: #333;
    font-size: 16px;
    font-weight: 700;
    left: -100px;
    background: #fff;
    border: 1px solid #e8e8e8;
    border-radius: 4px;
    -webkit-box-shadow: 0 0 2px 4px rgb(0 0 0 / 1%);
    box-shadow: 0 0 2px 4px rgb(0 0 0 / 1%);
    display: none;

    &:hover {
      display: block;
    }

    li {
      padding: 1px 12px;
    }
  }
}
</style>
<style lang="less">
.workflow-rule-popconfirm {
  .anticon-exclamation-circle {
    display: none;
  }
}

.a-tooltip-color {
  width: 305px !important;

  .ant-tooltip-inner {
    color: #333 !important;
  }
}
</style>
